#include "Connection.h"
#include "Thread.h"

#ifdef WIN32
#define ErrorCode() WSAGetLastError()
#define ERRWOULDBLOCK WSAEWOULDBLOCK
#else
#define ErrorCode() errno
#define ERRWOULDBOCK EWOULDBLOCK
#endif

Connection::Connection(sock_t sock)
{
	Socket = sock;
}

Connection::~Connection()
{
	Close();
}

bool Connection::Read(NetworkMessage* msg)
{
	if (!msg)
	{
		return false;
	}
	msg->Reset();
	unsigned char buffer[1024];
	int size = 0;
	int dSize = 0;
	size = recv(Socket, buffer, 2, 0);
	dSize = (buffer[1]) | (buffer[0] << 8); // network order: Big Endian
	if (size != 2 || (dSize > 32768))
	{
		if (ErrorCode() == ERRWOULDBLOCK)
		{
			return true;
		}
		return false; // some other error
	}
	int len = 0, read = 0;
	while (len < size)
	{
		read = (size - len > 1024) ? 1024 : size - len;
		dSize = recv(Socket, buffer, read, 0);
		if (dSize != read)
		{
			msg->Reset();
			return false; // error
		}
		msg->WriteRaw(buffer, read);
		len += read;
	}
	return true;
}

bool Connection::Write(NetworkMessage* msg)
{
	unsigned char buffer[32770];
	if (!msg)
	{
		return false;
	}
	int size = msg->GetLength();
	int flags = 0;
	if (size <= 0)
	{
		return true; // no msg to write
	}
	buffer[0] = (size >> 1) & 0xFF; // network order: Big Endian
	buffer[1] = (size & 0xFF);
	msg->GetBuffer(&(buffer[2]), 32768); // start at the 2nd position
#if defined WIN32 || defined __WINDOWS__
	unsigned long mode = 1; // set the socket to blocking mode
	ioctlsocket(Socket, FIONBIO, &mode);
	flags = 0;
#else
	flags = MSG_DONTWAIT;
#endif
	send(Socket, buffer, size + 2, flags);
#ifdef WIN32
	mode = 0;
	ioctlsocket(Socket, FIONBIO, &mode); // turn off blocking mode
#endif
	return true;
}

bool Connection::IsOpen()
{
	return Socket != 0;
}

void Connection::Close()
{
	if (IsOpen())
	{
		close(Socket);
		Socket = 0;
	}
}